package com.atguigu.tingshu.search.service.impl;
import cn.hutool.core.util.PageUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.FieldSort;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.SortOptions;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.aggregations.*;
import co.elastic.clients.elasticsearch._types.query_dsl.*;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Highlight;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.core.search.HitsMetadata;
import co.elastic.clients.elasticsearch.core.search.SourceConfig;
import co.elastic.clients.json.JsonData;
import com.alibaba.fastjson.JSON;
import com.atguigu.tingshu.album.client.CategoryFeignClient;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.model.album.AlbumAttributeValue;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.BaseCategory3;
import com.atguigu.tingshu.model.album.BaseCategoryView;
import com.atguigu.tingshu.model.search.AttributeValueIndex;
import com.atguigu.tingshu.model.user.UserInfo;
import com.atguigu.tingshu.query.search.AlbumIndexQuery;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.album.AlbumInfoDetailVo;
import com.atguigu.tingshu.vo.album.AlbumStatVo;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

import com.atguigu.tingshu.album.client.AlbumInfoFeignClient;
import com.atguigu.tingshu.model.search.AlbumInfoIndex;
import com.atguigu.tingshu.search.repository.AlbumInfoIndexRepository;
import com.atguigu.tingshu.search.service.SearchService;
import com.atguigu.tingshu.vo.album.TrackStatMqVo;
import com.atguigu.tingshu.vo.search.AlbumInfoIndexSearchVo;
import com.atguigu.tingshu.vo.search.AlbumInfoIndexVo;
import com.atguigu.tingshu.vo.search.AlbumSearchResponseVo;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;


@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class SearchServiceImpl implements SearchService {


    @Autowired
    private AlbumInfoIndexRepository albumInfoIndexRepository;
    @Autowired
    private AlbumInfoFeignClient albumInfoFeignClient;
    @Autowired
    private CategoryFeignClient categoryFeignClient;
    @Autowired
    private UserInfoFeignClient userInfoFeignClient;
    @Autowired
    private ElasticsearchClient elasticsearchClient;
    @Autowired
    private RedisTemplate<String , String> redisTemplate;
    @Autowired
    private RedissonClient redissonClient;



    @Override
    public void upperAlbum(Long albumId) {
        //构建albumInfoIndex对象封装专辑数据
        AlbumInfoIndex albumInfoIndex = new AlbumInfoIndex();
        albumInfoIndex.setId(albumId);

        CompletableFuture<AlbumInfo> cf1 = CompletableFuture.supplyAsync(() -> {

            //根据专辑id获取专辑基本数据
            Result<AlbumInfo> albumInfo = albumInfoFeignClient.getAlbumInfo(albumId);
            AlbumInfo data = albumInfo.getData();


            albumInfoIndex.setAlbumTitle(data.getAlbumTitle());
            albumInfoIndex.setAlbumIntro(data.getAlbumIntro());
            albumInfoIndex.setCoverUrl(data.getCoverUrl());
            albumInfoIndex.setIncludeTrackCount(data.getIncludeTrackCount());
            albumInfoIndex.setIsFinished(String.valueOf(data.getIsFinished()));
            albumInfoIndex.setPayType(data.getPayType());
            albumInfoIndex.setCreateTime(data.getCreateTime());


            //设置专辑的属性数据封装为attributeValueIndexList，
            List<AlbumAttributeValue> albumAttributeValueVoList = data.getAlbumAttributeValueVoList();
            List<AttributeValueIndex> attributeValueIndexList = albumAttributeValueVoList.stream().map(albumAttributeValue -> {
                AttributeValueIndex attributeValueIndex = new AttributeValueIndex();
                attributeValueIndex.setAttributeId(albumAttributeValue.getAttributeId());
                attributeValueIndex.setValueId(albumAttributeValue.getValueId());
                return attributeValueIndex;
            }).collect(Collectors.toList());
            albumInfoIndex.setAttributeValueIndexList(attributeValueIndexList);
            return data;

        });

        CompletableFuture<Void> cf2 = cf1.thenAcceptAsync(data -> {
            //根据三级分类id查询二级一级分类
            Result<BaseCategoryView> categoryViewResult = categoryFeignClient.findByCategoryBy3Id(data.getCategory3Id());
            BaseCategoryView categoryViewResultData = categoryViewResult.getData();
            albumInfoIndex.setCategory1Id(categoryViewResultData.getCategory1Id());
            albumInfoIndex.setCategory2Id(categoryViewResultData.getCategory2Id());
            albumInfoIndex.setCategory3Id(categoryViewResultData.getCategory3Id());

        });


        CompletableFuture<Void> cf3 = CompletableFuture.runAsync(() -> {
            //根据id查询专辑统计数据

            Result<AlbumStatVo> albumStatByAlbumId = albumInfoFeignClient.findAlbumStatByAlbumId(albumId);
            AlbumStatVo statByAlbumIdData = albumStatByAlbumId.getData();
            albumInfoIndex.setPlayStatNum(statByAlbumIdData.getPlayStatNum());
            albumInfoIndex.setSubscribeStatNum(statByAlbumIdData.getSubscribeStatNum());
            albumInfoIndex.setBuyStatNum(statByAlbumIdData.getBuyStatNum());
            albumInfoIndex.setCommentStatNum(statByAlbumIdData.getCommentStatNum());
            double hotScore = albumInfoIndex.getPlayStatNum() * 0.2 + albumInfoIndex.getSubscribeStatNum() * 0.3 + albumInfoIndex.getBuyStatNum() * 0.4 + albumInfoIndex.getCommentStatNum() * 0.1;
            albumInfoIndex.setHotScore(hotScore);
        });


        CompletableFuture<Void> cf4 = cf1.thenAcceptAsync(data -> {
            //设置专辑的作者名
            Result<UserInfo> userInfoById = userInfoFeignClient.findUserInfoById(data.getUserId());
            UserInfo userInfo = userInfoById.getData();
            albumInfoIndex.setAnnouncerName(userInfo.getNickname());
        });

        CompletableFuture.allOf(cf1, cf2, cf3, cf4).join();


        //根据专辑id获取专辑属性数据
        //根据三级分类id获取分类属性数据
        //根据用户id获取用户属性数据
        //把查询到的数据封装到AlbumInfoIndex对象中
        albumInfoIndexRepository.save(albumInfoIndex);
         // 将专辑的id保存到布隆过滤器中
        RBloomFilter<Object> bloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER);
        bloomFilter.add(albumId);
        log.info("保存专辑信息到bloomFilter中，albumId:{}", albumId);

    }

    @Override
    public void lowerAlbum(Long albumId) {
        albumInfoIndexRepository.deleteById(albumId);
        log.info("从ES中删除专辑信息，albumId:{}", albumId);
        //对布隆过滤器进行重建
        RBloomFilter<Object> bloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER_NEW);
        bloomFilter.tryInit(10000, 0.000001);

        //1.创建一个新的布隆过滤器，并从ES中查询未被删除的专辑id，然后将这些数据重新放入到布隆过滤器中
        Iterable<AlbumInfoIndex> infoIndexRepositoryAll = albumInfoIndexRepository.findAll();
        infoIndexRepositoryAll.forEach(AlbumInfoIndex -> {
            Long EsalumId = AlbumInfoIndex.getId();
            bloomFilter.add(EsalumId);
        });
        log.info("新的布隆过滤器重建完成");
        //删除之前的过滤器，并且将新的过滤器重命名
        String script = "redis.call('del', KEYS[1])\n" +
                "redis.call('del', \"{..KEYS[1]..}:config\")\n" +
                "redis.call('rename', KEYS[2], KEYS[1])\n" +
                "redis.call('rename', \"{..KEYS[2]..}:config\", \"{..KEYS[1]..}:config\")\n" +
                "return 1";
       // Long execute = redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), Arrays.asList(""));
         Long result =  redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), Arrays.asList(RedisConstant.ALBUM_BLOOM_FILTER,RedisConstant.ALBUM_BLOOM_FILTER_NEW));
    if (result ==1){
        log.info("新的布隆过滤器命名成功了");
    }
    }

    @SneakyThrows
    @Override
    public AlbumSearchResponseVo search(AlbumIndexQuery albumIndexQuery) {

        //使用ElasticSerachClient的方法查询

        //创建searchRequest对象
        SearchRequest searchRequest = buildSearchRequest(albumIndexQuery);

        //核心代码
        SearchResponse<AlbumInfoIndex> searchResponse = elasticsearchClient.search(searchRequest, AlbumInfoIndex.class);

        //从SearchResponse中解析对象
        AlbumSearchResponseVo albumSearchResponseVo = parseSearchResult(searchResponse, albumIndexQuery);

        //返回解析结果
        return albumSearchResponseVo;
    }


    //构建需要搜索的请求对象
    private SearchRequest buildSearchRequest(AlbumIndexQuery albumIndexQuery) {

        //创建BoolQuery对象
        BoolQuery.Builder boolQueryBuild = new BoolQuery.Builder();

        //拼接KeyWord搜索参数
        String KeyWord = albumIndexQuery.getKeyword();
        if (!StringUtils.isEmpty(KeyWord)) {
            Query query = QueryBuilders.multiMatch(builder -> builder.fields("albumTitle", "albumIntro").query(KeyWord));
            boolQueryBuild.must(query);
        } else {
            Query query = QueryBuilders.matchAll().build()._toQuery();
            boolQueryBuild.must(query);
        }
        //拼接分类搜索的参数拼接
        Long category1Id = albumIndexQuery.getCategory1Id();
        if (category1Id != null) {
            Query query = QueryBuilders.term(builder -> builder.field("category1Id").value(category1Id));
            boolQueryBuild.filter(query);
        }
        Long category2Id = albumIndexQuery.getCategory2Id();
        if (category2Id != null) {
            Query query = QueryBuilders.term(builder -> builder.field("category2Id").value(category2Id));
            boolQueryBuild.filter(query);
        }
        Long category3Id = albumIndexQuery.getCategory3Id();
        if (category3Id != null) {
            Query query = QueryBuilders.term(builder -> builder.field("category3Id").value(category3Id));
            boolQueryBuild.filter(query);
        }


        //拼接专辑搜索的搜索条件拼接
        List<String> attributeList = albumIndexQuery.getAttributeList();
        if (!StringUtils.isEmpty(attributeList)) {
            for (String attributeAndValue : attributeList) {
                String[] split = attributeAndValue.split(":");
                String attrId = split[0];
                String attrValue = split[1];
                BoolQuery boolQuery = QueryBuilders.bool()
                        .must(QueryBuilders.term(builder -> builder.field("attributeValueIndexList.attributeId").value(attrId)))
                        .must(QueryBuilders.term(builder -> builder.field("attributeValueIndexList.valueId").value(attrValue))).build();
                Query query = QueryBuilders.nested(builder -> builder.path("attributeValueIndexList")
                        .query(boolQuery._toQuery()));
                boolQueryBuild.filter(query);

            }
        }

        //创建Query对象 封装请求参数
        Query query = new Query.Builder()
                .bool(boolQueryBuild.build())
                .build();

        //创建SearchRequestBuilder对象
//        SearchRequest.Builder builder = new SearchRequest.Builder();
//        builder.query(query).source(new SourceConfig.Builder().fetch(false).build());

        // 创建一个SearchRquestBuilder对象
        SearchRequest.Builder builder = new SearchRequest.Builder();
        builder.index("albuminfo") ;                // 给builder对象设置索引库的名称
        builder.query(query) ;

        String orderInfo = albumIndexQuery.getOrder();

        //创建fieldSaort对象
        FieldSort.Builder fieldSortBuilder = new FieldSort.Builder();
        if (!StringUtils.isEmpty(orderInfo)) {

            String[] split = orderInfo.split(":");
            String sortField = split[0];
            String order = split[1];

            switch (sortField) {
                case "1":
                    fieldSortBuilder.field("hotScore").order("asc".equalsIgnoreCase(order) ? SortOrder.Asc : SortOrder.Desc);
                    break;
                case "2":
                    fieldSortBuilder.field("playStatNum").order("asc".equalsIgnoreCase(order) ? SortOrder.Asc : SortOrder.Desc);
                    break;
                case "3":
                    fieldSortBuilder.field("createTime").order("asc".equalsIgnoreCase(order) ? SortOrder.Asc : SortOrder.Desc);
                    break;
            }
        } else {
            fieldSortBuilder.field("hotScore").order(SortOrder.Desc);
        }

        //创建sortOptions对象
        SortOptions sortOptions = new SortOptions.Builder()
                .field(fieldSortBuilder.build())
                .build();
        builder.sort(sortOptions);

        // 设置分页查询
        builder.from((albumIndexQuery.getPageNo() - 1) * albumIndexQuery.getPageSize()).size(albumIndexQuery.getPageSize());

        // 设置高亮的参数
        if (!StringUtils.isEmpty(KeyWord)) {
            Highlight highlight = new Highlight.Builder()
                    .fields("albumTitle", highlightBuilder -> highlightBuilder.preTags("<font color='red'>").postTags("</font>"))
                    .fields("albumIntro", highlightBuilder -> highlightBuilder.preTags("<font color='red'>").postTags("</font>"))
                    .build();
            builder.highlight(highlight);
        }

        SearchRequest searchRequest = builder.build();
        log.info("dsl: {}", searchRequest.toString());
        //给builder对象设置索引库名称
        builder.index("albuminfo");
        return searchRequest;
    }

    //解析响应结果数据
    private AlbumSearchResponseVo parseSearchResult(SearchResponse<AlbumInfoIndex> searchResponse, AlbumIndexQuery albumIndexQuery) {
        HitsMetadata<AlbumInfoIndex> hitsMetadata = searchResponse.hits();


        List<Hit<AlbumInfoIndex>> hits = hitsMetadata.hits();
        List<AlbumInfoIndexVo> albumInfoIndexVoList = hits.stream().map(hit -> {
            AlbumInfoIndex albumInfoIndex = hit.source();
            AlbumInfoIndexVo albumInfoIndexVo = new AlbumInfoIndexVo();
            BeanUtils.copyProperties(albumInfoIndex, albumInfoIndexVo);

            // 从搜索结果中获取高量的结果，使用高亮的结果替换原始文档中的数据
            Map<String, List<String>> highlight = hit.highlight();
            if (!CollectionUtils.isEmpty(highlight)) {

                List<String> albumTitleHighlightList = highlight.get("albumTitle");
                if (!CollectionUtils.isEmpty(albumTitleHighlightList)) {
                    String albumTitleHighlight = albumTitleHighlightList.get(0);
                    albumInfoIndexVo.setAlbumTitle(albumTitleHighlight);
                }

                List<String> albumIntroHighlightList = highlight.get("albumIntro");
                if (!CollectionUtils.isEmpty(albumIntroHighlightList)) {
                    String albumIntroHighlight = albumIntroHighlightList.get(0);
                    albumInfoIndexVo.setAlbumIntro(albumIntroHighlight);
                }

            }
            return albumInfoIndexVo;
        }).collect(Collectors.toList());
        // 创建AlbumSearchResponseVo对象，封装搜索结果数据
        AlbumSearchResponseVo albumSearchResponseVo = new AlbumSearchResponseVo();
        albumSearchResponseVo.setList(albumInfoIndexVoList);

        // 分页相关参数的设定
        long total = hitsMetadata.total().value();
        albumSearchResponseVo.setTotal(total);
        albumSearchResponseVo.setPageSize(albumIndexQuery.getPageSize());
        albumSearchResponseVo.setPageNo(albumIndexQuery.getPageNo());
        Integer totalPage = PageUtil.totalPage((int) total, albumIndexQuery.getPageSize());
        albumSearchResponseVo.setTotalPages(Long.parseLong(totalPage.toString()));

        return albumSearchResponseVo;
    }


    public void upperAlbum1(Long albumId) {

        //构建albumInfoIndex对象封装专辑数据
        AlbumInfoIndex albumInfoIndex = new AlbumInfoIndex();
        albumInfoIndex.setId(albumId);

        //根据专辑id获取专辑基本数据
        Result<AlbumInfo> albumInfo = albumInfoFeignClient.getAlbumInfo(albumId);
        AlbumInfo data = albumInfo.getData();


        albumInfoIndex.setAlbumTitle(data.getAlbumTitle());
        albumInfoIndex.setAlbumIntro(data.getAlbumIntro());
        albumInfoIndex.setCoverUrl(data.getCoverUrl());
        albumInfoIndex.setIncludeTrackCount(data.getIncludeTrackCount());
        albumInfoIndex.setIsFinished(String.valueOf(data.getIsFinished()));
        albumInfoIndex.setPayType(data.getPayType());
        albumInfoIndex.setCreateTime(data.getCreateTime());


        //设置专辑的属性数据封装为attributeValueIndexList，
        List<AlbumAttributeValue> albumAttributeValueVoList = data.getAlbumAttributeValueVoList();
        List<AttributeValueIndex> attributeValueIndexList = albumAttributeValueVoList.stream().map(albumAttributeValue -> {
            AttributeValueIndex attributeValueIndex = new AttributeValueIndex();
            attributeValueIndex.setAttributeId(albumAttributeValue.getAttributeId());
            attributeValueIndex.setValueId(albumAttributeValue.getValueId());
            return attributeValueIndex;
        }).collect(Collectors.toList());
        albumInfoIndex.setAttributeValueIndexList(attributeValueIndexList);

        //根据三级分类id查询二级一级分类
        Result<BaseCategoryView> categoryViewResult = categoryFeignClient.findByCategoryBy3Id(data.getCategory3Id());
        BaseCategoryView categoryViewResultData = categoryViewResult.getData();
        albumInfoIndex.setCategory1Id(categoryViewResultData.getCategory1Id());
        albumInfoIndex.setCategory2Id(categoryViewResultData.getCategory2Id());
        albumInfoIndex.setCategory3Id(categoryViewResultData.getCategory3Id());


        //根据id查询专辑统计数据

        Result<AlbumStatVo> albumStatByAlbumId = albumInfoFeignClient.findAlbumStatByAlbumId(albumId);
        AlbumStatVo statByAlbumIdData = albumStatByAlbumId.getData();
        albumInfoIndex.setPlayStatNum(statByAlbumIdData.getPlayStatNum());
        albumInfoIndex.setSubscribeStatNum(statByAlbumIdData.getSubscribeStatNum());
        albumInfoIndex.setBuyStatNum(statByAlbumIdData.getBuyStatNum());
        albumInfoIndex.setCommentStatNum(statByAlbumIdData.getCommentStatNum());
        double hotScore = albumInfoIndex.getPlayStatNum() * 0.2 + albumInfoIndex.getSubscribeStatNum() * 0.3 + albumInfoIndex.getBuyStatNum() * 0.4 + albumInfoIndex.getCommentStatNum() * 0.1;
        albumInfoIndex.setHotScore(hotScore);


        //设置专辑的作者名
        Result<UserInfo> userInfoById = userInfoFeignClient.findUserInfoById(data.getUserId());
        UserInfo userInfo = userInfoById.getData();
        albumInfoIndex.setAnnouncerName(userInfo.getNickname());


        //根据专辑id获取专辑属性数据
        //根据三级分类id获取分类属性数据
        //根据用户id获取用户属性数据
        //把查询到的数据封装到AlbumInfoIndex对象中
        albumInfoIndexRepository.save(albumInfoIndex);

    }




    @Override
    public List<AlbumInfoIndexSearchVo> channel(Long category1Id) throws IOException {

        // 根据一级分类的id查找置顶的三级分类数据
        Result<List<BaseCategory3>> result = categoryFeignClient.findTopBaseCategory3(category1Id);
        List<BaseCategory3> baseCategory3List = result.getData();

        // 创建TermsQueryField对象
        List<FieldValue> fieldValueList = baseCategory3List.stream().map(baseCategory3 -> {
            Long id = baseCategory3.getId();
            FieldValue fieldValue = new FieldValue.Builder().longValue(id).build();
            return fieldValue;
        }).collect(Collectors.toList());
        TermsQueryField termsQueryField = new TermsQueryField.Builder()
                .value(fieldValueList)
                .build();

        // 创建一个BoolQuery对象
        BoolQuery boolQuery = QueryBuilders.bool()
                .must(builder -> builder.term(QueryBuilders.term().field("category1Id").value(category1Id).build()))
                .must(builder -> builder.terms(QueryBuilders.terms().field("category3Id").terms(termsQueryField).build()))
                .build();
        Query query = new Query.Builder()
                .bool(boolQuery)
                .build();

        // 创建Aggregation对象
        SortOptions sortOptions = new SortOptions.Builder().field(builder -> builder.field("hotScore").order(SortOrder.Desc)).build();
        Aggregation albumInfoAggregation = new Aggregation.Builder().topHits(builder -> builder.size(6).sort(sortOptions)).build();

        // 创建一个Aggregation对象
        Aggregation aggregation = new Aggregation.Builder()
                .terms(builder -> builder.field("category3Id")
                        .size(10))
                .aggregations("albumInfoAgg", albumInfoAggregation)
                .build();

        // 创建SearchRequest对象
        SourceConfig sourceConfig = new SourceConfig.Builder().fetch(false).build();
        SearchRequest searchRequest = new SearchRequest.Builder()
                .index("albuminfo")
                .query(query)
                .source(sourceConfig)
                .aggregations("category3IdAgg", aggregation)
                .build();

        // 执行搜索
        SearchResponse<AlbumInfoIndex> indexSearchResponse = elasticsearchClient.search(searchRequest, AlbumInfoIndex.class);
        Map<String, Aggregate> aggregations = indexSearchResponse.aggregations();
        Aggregate aggregate = aggregations.get("category3IdAgg");
        LongTermsAggregate longTermsAggregate = (LongTermsAggregate) aggregate._get();
        Buckets<LongTermsBucket> bucketBuckets = longTermsAggregate.buckets();
        List<LongTermsBucket> longTermsBuckets = bucketBuckets.array();

        List<AlbumInfoIndexSearchVo> albumInfoIndexSearchVos = new ArrayList<>();
        for (LongTermsBucket longTermsBucket : longTermsBuckets) {

            AlbumInfoIndexSearchVo albumInfoIndexSearchVo = new AlbumInfoIndexSearchVo();

            // 获取三级分类的id
            long c3Id = longTermsBucket.key();
            BaseCategory3 dbBaseCategory3 = baseCategory3List.stream().filter(baseCategory3 -> baseCategory3.getId() == c3Id)
                    .collect(Collectors.toList()).get(0);

            Map<String, Aggregate> aggregateMap = longTermsBucket.aggregations();
            Aggregate albumInfoAgg = aggregateMap.get("albumInfoAgg");
            TopHitsAggregate topHitsAggregate = (TopHitsAggregate) albumInfoAgg._get();
            HitsMetadata<JsonData> hitsMetadata = topHitsAggregate.hits();
            List<Hit<JsonData>> hits = hitsMetadata.hits();

            // 获取文档数据
            List<AlbumInfoIndex> albumInfoIndexList = hits.stream().map(hit -> {
                JsonData jsonData = hit.source();
                AlbumInfoIndex albumInfoIndex = jsonData.to(AlbumInfoIndex.class);
                return albumInfoIndex;
            }).collect(Collectors.toList());

            albumInfoIndexSearchVo.setBaseCategory3(dbBaseCategory3);
            albumInfoIndexSearchVo.setList(albumInfoIndexList);

            albumInfoIndexSearchVos.add(albumInfoIndexSearchVo);

        }

        return albumInfoIndexSearchVos;
    }

    @SneakyThrows
    @Override
    public void updateLatelyAlbumRanking() {

        //创建Query对象
        Query query = new Query.Builder()
                .matchAll(QueryBuilders.matchAll().build())
                .build();
        //创建sourceConfig对象
        SourceConfig sourceConfig = new SourceConfig.Builder()
                .fetch(false)
                .build();

        // 创建一个Aggregation对象
        Aggregation.Builder.ContainerBuilder containerBuilder = new Aggregation.Builder().terms(builder -> builder.field("category1Id").size(40));

        String[] rankingDimensionArray = new String[]{"hotScore", "playStatNum", "subscribeStatNum", "buyStatNum", "commentStatNum"};
        for (String rankingDimension : rankingDimensionArray) {
            SortOptions sortOptions = new SortOptions.Builder()
                    .field(builder -> builder.field(rankingDimension).order(SortOrder.Desc))
                    .build();
            Aggregation aggregation = new Aggregation.Builder().topHits(builder -> builder.size(10).sort(sortOptions)).build();
            containerBuilder.aggregations(rankingDimension + "TopHitAgg", aggregation);
        }
        //从es中进行统计查询
        SearchRequest searchRequest = new SearchRequest.Builder()
                .index("albuminfo")
                .query(query)
                .source(sourceConfig)
                .aggregations("category1IdAgg", containerBuilder.build())
                .build();

        SearchResponse<AlbumInfoIndex> searchResponse = elasticsearchClient.search(searchRequest, AlbumInfoIndex.class);
        //将统计的结果保存到Redis中

        // 将统计查询的结果数据存储到Redis
        Map<String, Aggregate> aggregations = searchResponse.aggregations();
        Aggregate aggregate = aggregations.get("category1IdAgg");
        LongTermsAggregate longTermsAggregate = (LongTermsAggregate) aggregate._get();
        Buckets<LongTermsBucket> buckets = longTermsAggregate.buckets();
        List<LongTermsBucket> termsBuckets = buckets.array();
        for (LongTermsBucket termsBucket : termsBuckets) {

            long category1Id = termsBucket.key();       // 获取一级分类的id
            String rankingRedisKey = RedisConstant.RANKING_KEY_PREFIX + category1Id;

            Map<String, Aggregate> aggregateMap = termsBucket.aggregations();
            for (String rankingDimension : rankingDimensionArray) {

                Aggregate agg = aggregateMap.get(rankingDimension + "TopHitAgg");
                TopHitsAggregate topHitsAggregate = (TopHitsAggregate) agg._get();
                HitsMetadata<JsonData> hitsMetadata = topHitsAggregate.hits();
                List<Hit<JsonData>> hits = hitsMetadata.hits();
                List<AlbumInfoIndex> albumInfoIndexList = new ArrayList<>();
                for (Hit<JsonData> hit : hits) {
                    AlbumInfoIndex albumInfoIndex = hit.source().to(AlbumInfoIndex.class);
                    albumInfoIndexList.add(albumInfoIndex);
                }

                // 把数据统计到结果数据存储到Redis中
                /**
                 * 应该使用Redis中哪一种数据类型完成数据的存储？
                 * string , List , set , hash , zset
                 *
                 * 后期在进行查询的时候是需要按照一级分类的id以及统计维度的字符串进行查询， hash
                 * 使用hash结果进行存储，针对每一个分类只需要再Redis中形成1个key
                 */

                redisTemplate.opsForHash().put(rankingRedisKey, rankingDimension, JSON.toJSONString(albumInfoIndexList));
            }

        }
    }

    @Override
    public List<AlbumInfoIndex> findRankingList(Long category1Id, String dimension) {

        //从Redis中获取数据
        String rankingRedisKey = RedisConstant.RANKING_KEY_PREFIX + category1Id;
        Object obj = redisTemplate.opsForHash().get(rankingRedisKey, dimension);
        if (obj != null) {
            String jsonString = obj.toString();
            List<AlbumInfoIndex> albumInfoIndexList = JSON.parseArray(jsonString, AlbumInfoIndex.class);
           return albumInfoIndexList;
        }else {
            return new ArrayList<>();
        }
    }

    @Override
    public void albumStatUpdate(TrackStatMqVo trackStatMqVo) {
        //获取专辑Id
        Long albumId = trackStatMqVo.getAlbumId();
        //从ES中根据专辑Id查询
        Optional<AlbumInfoIndex> repository = albumInfoIndexRepository.findById(albumId);
        //获取查询到的数据
        AlbumInfoIndex albumInfoIndex = repository.get();

        String statType = trackStatMqVo.getStatType();
        switch (statType){
            case SystemConstant.ALBUM_STAT_PLAY:
                //如果是播放量，则修改播放量的值
                albumInfoIndex.setPlayStatNum(trackStatMqVo.getCount());
            case SystemConstant.ALBUM_STAT_SUBSCRIBE:
                //如果是订阅量，则修改订阅量的值
                albumInfoIndex.setSubscribeStatNum(trackStatMqVo.getCount());
                break;
            case SystemConstant.ALBUM_STAT_BROWSE:
                //如果是购买量，则修改购买量的值
                albumInfoIndex.setBuyStatNum(trackStatMqVo.getCount());
                break;
            case SystemConstant.ALBUM_STAT_COMMENT:
                //如果是评论量，则修改评论量的值
                albumInfoIndex.setCommentStatNum(trackStatMqVo.getCount());
                break;
        }
        albumInfoIndexRepository.save(albumInfoIndex);
        log.info("专辑的统计数据同步完毕..........");
    }


}